set nocompatible
" -----------------
" functions
" -----------------
function! Trim(str) abort
    return substitute(a:str, "^\s\+\|\s\+$", "", "g")
endfunction
function! Expand(path) abort
    return fnameescape(substitute(expand(a:path), "\\", '/', 'g'))
endfunction
function! FileDir(file) abort
    return expand(a:file . ':p:h')
endfunction
function! GetVisualSelection() abort
    let [line_start, column_start] = getpos("'<")[1:2]
    let [line_end, column_end] = getpos("'>")[1:2]
    let lines = getline(line_start, line_end)
    if len(lines) == 0
        return ""
    endif
    let lines[-1] = lines[-1][:column_end - (&selection == "inclusive" ? 1 : 2)]
    let lines[0] = lines[0][column_start - 1:]
    return join(lines, "\n")
endfunction
function! StringToFloat(str, ...) abort
    let str = a:str
    if a:0 == 0
        let digit = 1
    else
        let digit = a:1
    endif
    let lst = split(str, "\\.")
    let rst = []
    for each in lst[1:]
        if len(each) >= digit
            let e = each[:digit]
        else
            let e = repeat('0', digit - len(each)) . each
        endif
        call add(rst, e)
    endfor
    return str2float(lst[0] . '.' . join(rst, ''))
endfunction
function! TripTrailingWhiteSpace() abort
    let _s=@/
    let l = line(".")
    let c = col(".")
    " do the business:
    %s/\s\+$//e
    " clean up: restore previous search history, and cursor position
    let @/=_s
    call cursor(l, c)
endfunction
augroup TripSpaces
    autocmd FileType vim,c,cpp,java,go,php,javascript,typescript,python,rust,twig,xml,yml,perl,sql,r,conf,lua
                \ autocmd! BufWritePre <buffer> :call TripTrailingWhiteSpace()
augroup END
nnoremap <silent>d<space> :call TripTrailingWhiteSpace()<Cr>
" -----------------------------------
" filetypes definition
" -----------------------------------
let g:c_filetypes = get(g:, 'c_filetypes', ["c", "cpp", "objc", "objcpp", "cuda"])
let g:web_filetypes = get(g:, 'web_filetypes', ['php', 'html', 'css', 'scss', 'wxss', 'wxml', 'xml', 'toml', 'javascript', 'typescript', 'vue'])
let g:highlight_filetypes = get(g:, 'highlight_filetypes', ['python', 'r', 'vim', 'markdown', 'lua'])
" -----------------------------------
" pattern
" -----------------------------------
let g:root_patterns = get(g:, 'root_patterns', [".git", ".hg", ".svn", ".root", ".env", ".vscode", '.idea', ".ccls", ".project"])
let g:todo_patterns = "(TODO|FIXME|WARN|ERROR|BUG)"
let g:note_patterns = "(NOTE|XXX|HINT|STEP|ETC|In\\[\\d\*\\])"
" -----------------------------------
" map
" -----------------------------------
map ÏP <F1>
map ÏQ <F2>
map ÏR <F3>
map ÏS <F4>
map <F1>  <Nop>
map <F2>  <Nop>
map <F3>  <Nop>
map <F4>  <Nop>
map <F5>  <Nop>
map <F6>  <Nop>
map <F7>  <Nop>
map <F8>  <Nop>
map <F9>  <Nop>
map <F10> <Nop>
map <F11> <Nop>
map <F12> <Nop>
map <C-q> <Nop>
map <C-s> <Nop>
map <C-i> <Nop>
map <C-z> <Nop>
nnoremap gx <Nop>
xnoremap gx <Nop>
nnoremap s  <Nop>
nnoremap S  <Nop>
nnoremap ,  <Nop>
xnoremap ,  <Nop>
nnoremap -  <Nop>
nnoremap =  <Nop>
nnoremap _  <Nop>
nnoremap +  <Nop>
" enhanced remap
xmap >> >gv
xmap << <gv
nnoremap <silent> gj j
nnoremap <silent> gk k
nnoremap <expr> k (v:count > 1 ? "m'" . v:count : '') . 'gk'
nnoremap <expr> j (v:count > 1 ? "m'" . v:count : '') . 'gj'
" z remap
nnoremap zs <Nop>
nnoremap zS <Nop>
nnoremap zw <Nop>
nnoremap zW <Nop>
nnoremap zg <Nop>
nnoremap zG <Nop>
nnoremap zl zL
nnoremap zh zH
nnoremap zr zR
nnoremap z= zT
nnoremap z- zB
nnoremap ZT zt
nnoremap zt z<CR>
" ------------------------
" search
" ------------------------
nmap gI 2g;a
xnoremap / /<C-u><C-R>=GetVisualSelection()<Cr>
xnoremap ? ?<C-u><C-R>=GetVisualSelection()<Cr>
xnoremap . :<C-u>normal .<Cr>
xnoremap <Cr> :<C-u>%s/<C-R>=GetVisualSelection()<Cr>/
" ------------------------
" case change
" ------------------------
nnoremap ZU m1gUiw`1
nnoremap ZD m1guiw`1
" ------------------------
" home end
" ------------------------
cmap <C-a> <Home>
cmap <C-e> <End>
imap <expr><C-b> pumvisible()? "\<C-b>":"\<C-o>I"
imap <expr><C-f> pumvisible()? "\<C-f>":"\<C-o>A"
imap <expr><C-a> pumvisible()? "\<C-a>":"\<C-o>0"
nnoremap H ^
xnoremap H ^
onoremap H ^
nnoremap L g_
xnoremap L g_
onoremap L g_
nnoremap $ g_
xnoremap $ g_
onoremap $ g_
nnoremap g_ $
xnoremap g_ $
onoremap g_ $
" ------------------------
" yank
" ------------------------
nnoremap <expr> gp '`[' . strpart(getregtype(), 0, 1) . '`]'
xnoremap zp "_c<ESC>p"
xnoremap zP "_c<ESC>P"
if exists("##ModeChanged")
    au ModeChanged *:s set clipboard=
    au ModeChanged s:* set clipboard=unnamedplus
endif
" ------------------------------
" load pack in OPT_PATH
" ------------------------------
function! s:plug_local(pack)
    let pack = a:pack
    if exists(':packadd')
        execute "packadd " . pack
    else
        for opt_path in [$CLONE_OPT_PATH, $FORK_OPT_PATH, $LEO_OPT_PATH]
            let rtp_add = 0
            let dir = expand(opt_path . "/" . pack)
            let after = expand(opt_path . "/" . pack . "/after")
            if isdirectory(dir)
                execute "set rtp^=" . dir
                let rtp_add = 1
            endif
            if isdirectory(after)
                execute "set rtp+=" . after
            endif
            if rtp_add
                break
            endif
        endfor
    endif
    let g:leovim_installed[tolower(pack)] = 1
endfunction
command! -nargs=+ PlugAddOpt call <sid>plug_local(<args>)
" ------------------------------
" intergrated packs
" ------------------------------
PlugAddOpt 'vim-eunuch'
" conflict marker
let g:conflict_marker_enable_mappings = 0
PlugAddOpt 'conflict-marker.vim'
nnoremap <leader>cf /\v^[<\|=>]{7}( .*\|$)<CR>
nnoremap <leader>cF ?\v^[<\|=>]{7}( .*\|$)<CR>
nnoremap <leader>ct :ConflictMarkerThemselves<Cr>
nnoremap <leader>co :ConflictMarkerOurselves<Cr>
nnoremap <leader>cn :ConflictMarkerNone<Cr>
nnoremap <leader>cb :ConflictMarkerBoth<Cr>
nnoremap <leader>c; :ConflictMarkerNextHunk<Cr>
nnoremap <leader>c, :ConflictMarkerPrevHunk<Cr>
" ------------------------
" quick jump in buffer
" ------------------------
let g:search_labels = "123456789asdghklqwertyuiopzxcvbnmfj,;"
if has('nvim-0.8')
    PlugAddOpt 'flash.nvim'
    luafile $LUA_PATH/flash.lua
else
    let g:clever_f_smart_case = 1
    let g:clever_f_repeat_last_char_inputs = ['<Tab>']
    nmap ; <Plug>(clever-f-repeat-forward)
    xmap ; <Plug>(clever-f-repeat-forward)
    nmap ,, <Plug>(clever-f-repeat-back)
    xmap ,, <Plug>(clever-f-repeat-back)
    PlugAddOpt 'clever-f.vim'
endif
if has('nvim-0.9')
    PlugAddOpt 'hop.nvim'
    luafile $LUA_PATH/hop.lua
elseif !has('g:vscode')
    PlugAddOpt 'vim-easymotion'
    PlugAddOpt 'vim-easymotion-chs'
    source $CFG_PATH/easymotion.vim
endif
" ------------------------
" surround
" ------------------------
nmap ss viw<Plug>VSurround
nmap sL v$<Plug>VSurround
nmap sH v^<Plug>VSurround
nmap sn vt<Space><Plug>VSurround
nmap sp vT<Space><Plug>VSurround
" --------------------------
" textobj
" --------------------------
if exists('*search') && exists('*getpos')
    PlugAddOpt 'vim-textobj-user'
    PlugAddOpt 'vim-textobj-function'
    PlugAddOpt 'vim-textobj-syntax'
    PlugAddOpt 'vim-textobj-uri'
    PlugAddOpt 'vim-textobj-line'
    PlugAddOpt 'targets.vim'
    nmap <leader>vf vafo
    nmap <leader>vF vifo
    nmap <leader>vc vaco
    nmap <leader>vC vico
    nmap <leader>vu viu
    nmap <leader>vU vau
    nmap <leader>vl vil
    nmap <leader>vL val
    nmap <leader>vt vi%
    nmap <leader>vT va%
    nmap <leader>va via
    nmap <leader>vA vaa
    nmap <leader>vb vib
    nmap <leader>vB vaB
    nmap <leader>vn vin
    nmap <leader>vN vaN
    " goto first/last indent
    nmap <leader>vi viio
    nmap <leader>vI vaio
    nmap sI viio<C-[>^
    nmap si vii<C-[>^
    " --------------------------
    " sandwich
    " --------------------------
    PlugAddOpt 'vim-sandwich'
    xmap is <Plug>(textobj-sandwich-auto-i)
    xmap as <Plug>(textobj-sandwich-auto-a)
    omap is <Plug>(textobj-sandwich-auto-i)
    omap as <Plug>(textobj-sandwich-auto-a)
    xmap iq <Plug>(textobj-sandwich-query-i)
    xmap aq <Plug>(textobj-sandwich-query-a)
    omap iq <Plug>(textobj-sandwich-query-i)
    omap aq <Plug>(textobj-sandwich-query-a)
    nmap <leader>vs vis
    nmap <leader>vS vas
    nmap <leader>vq viq
    nmap <leader>vQ vaq
    " ------------------------
    " find block
    " ------------------------
    let s:block_str = '^# In\[\d*\]\|^# %%\|^# STEP\d\+'
    function! BlockA()
        let beginline = search(s:block_str, 'ebW')
        if beginline == 0
            normal! gg
        endif
        let head_pos = getpos('.')
        let endline  = search(s:block_str, 'eW')
        if endline == 0
            normal! G
        endif
        let tail_pos = getpos('.')
        return ['V', head_pos, tail_pos]
    endfunction
    function! BlockI()
        let beginline = search(s:block_str, 'ebW')
        if beginline == 0
            normal! gg
            let beginline = 1
        else
            normal! j
        endif
        let head_pos = getpos('.')
        let endline = search(s:block_str, 'eW')
        if endline == 0
            normal! G
        elseif endline > beginline
            normal! k
        endif
        let tail_pos = getpos('.')
        return ['V', head_pos, tail_pos]
    endfunction
    " select a block
    call textobj#user#plugin('block', {
                \ 'block': {
                    \  'select-a-function': 'BlockA',
                    \  'select-a': 'aB',
                    \  'select-i-function': 'BlockI',
                    \  'select-i': 'iB',
                    \  'region-type': 'V'
                    \ },
                    \ })
    nmap <leader>vv viB
    nmap <leader>vV vaB
endif
